package com.test.ayi.util;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Slf4j
@Component
public class MultiLevelCache {

    @Resource
    private RedisUtil redisUtil;

    // Caffeine本地缓存
    private final Cache<String, Object> localCache = Caffeine.newBuilder()
            .initialCapacity(100)
            .maximumSize(500)
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .recordStats()
            .build();

    /**
     * 获取数据，优先从本地缓存获取，没有则从Redis获取，都没有则从数据源获取
     *
     * @param key 缓存key
     * @param dbFallback 数据源获取函数
     * @param expireSeconds Redis过期时间（秒）
     * @return 缓存数据
     */
    public Object getWithMultiLevel(String key, Function<String, Object> dbFallback, long expireSeconds) {
        // 1. 先从本地缓存获取
        Object value = localCache.getIfPresent(key);
        if (value != null) {
            log.debug("从本地缓存中获取数据, key: {}", key);
            return value;
        }

        // 2. 从Redis获取
        value = redisUtil.get(key);
        if (value != null) {
            log.debug("从Redis中获取数据, key: {}", key);
            // 放入本地缓存
            localCache.put(key, value);
            return value;
        }

        // 3. 从数据源获取
        value = dbFallback.apply(key);
        if (value != null) {
            log.debug("从数据源中获取数据, key: {}", key);
            // 放入Redis
            redisUtil.set(key, value, expireSeconds);
            // 放入本地缓存
            localCache.put(key, value);
        }

        return value;
    }

    /**
     * 更新数据，同时更新多级缓存
     */
    public void put(String key, Object value, long expireSeconds) {
        // 更新Redis
        redisUtil.set(key, value, expireSeconds);
        // 更新本地缓存
        localCache.put(key, value);
    }

    /**
     * 删除缓存
     */
    public void delete(String key) {
        // 删除Redis缓存
        redisUtil.del(key);
        // 删除本地缓存
        localCache.invalidate(key);
    }

    /**
     * 获取本地缓存统计信息
     */
    public String getCacheStats() {
        return localCache.stats().toString();
    }
}
